package com.yj.timecapsule.service.diaries.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.yj.timecapsule.common.context.LoginUserContext;
import com.yj.timecapsule.common.enums.ErrorCode;
import com.yj.timecapsule.common.error.BusinessException;
import com.yj.timecapsule.common.response.PageResponse;
import com.yj.timecapsule.common.utils.AsyncTaskUtil;
import com.yj.timecapsule.entity.diaries.Diaries;
import com.yj.timecapsule.entity.user.Friends;
import com.yj.timecapsule.entity.user.Users;
import com.yj.timecapsule.entity.diaries.DiariesWithBLOBs;
import com.yj.timecapsule.entity.diaries.dto.DiariesDto;
import com.yj.timecapsule.entity.diaries.dto.DiariesQueryDto;
import com.yj.timecapsule.entity.diaries.vo.DiariesDetailVo;
import com.yj.timecapsule.entity.diaries.vo.DiariesVo;
import com.yj.timecapsule.mapper.CommentsMapper;
import com.yj.timecapsule.mapper.DiariesMapper;
import com.yj.timecapsule.mapper.FriendsMapper;
import com.yj.timecapsule.mapper.LikesMapper;
import com.yj.timecapsule.service.diaries.DiariesService;
import com.yj.timecapsule.service.user.UserService;
import jakarta.annotation.Resource;
import org.springframework.objenesis.instantiator.basic.NullInstantiator;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;

@Service
public class DiariesServiceImpl implements DiariesService {
    private static final long SEVEN_DAYS_MILLIS = 7 * 24 * 60 * 60 * 1000L;
    @Resource
    private DiariesMapper diariesMapper;
    @Resource
    private CommentsMapper commentsMapper;
    @Resource
    private LikesMapper likesMapper;
    @Resource
    private UserService userService;
    @Resource
    private FriendsMapper friendsMapper;
    @Override
    public PageResponse<DiariesVo> load(DiariesQueryDto dto) {
        Long userId = LoginUserContext.getId();
        List<Friends> friends = friendsMapper.selectByUserId(userId);
        List<Long> userIds = friends.stream().map(Friends::getUserId).toList();
        PageHelper.startPage(dto.getPage(), dto.getSize());

        Page<DiariesWithBLOBs> diariesPage = diariesMapper.selectPageByKeyWordAndUserIds(dto.getKeyWord(),userIds);

        List<DiariesWithBLOBs> diariesList = diariesPage.getResult();
        List<DiariesVo> voList = BeanUtil.copyToList(diariesList, DiariesVo.class);


        CompletableFuture<List<DiariesVo>> future = CompletableFuture.supplyAsync(() -> {
            List<DiariesVo> updatedVoList = new ArrayList<>(voList.size());
            for (DiariesVo vo : voList) {
                Long id = vo.getId();
                Long commentsCount = commentsMapper.selectCountByDiariesId(id);
                Long likesCount = likesMapper.selectCountByDiariesId(id);
                Users users = userService.getInfo(getUserIdFromDiariesList(diariesList, id));
                vo.setCommentNum(commentsCount);
                vo.setLikeNum(likesCount);
                vo.setUserName(users.getUsername());
                updatedVoList.add(vo);
            }
            return updatedVoList;
        });

        List<DiariesVo> resultVoList = future.join();
        diariesPage.forEach(diariesWithBLOBs -> {
            List<String> images = buildImages(diariesWithBLOBs.getImages());
            resultVoList.forEach(vo -> {
                if (vo.getId().equals(diariesWithBLOBs.getId())) {
                    vo.setImages(images);
                }
            });
        });


        return PageResponse.create(diariesPage.getTotal(), resultVoList);
    }


    @Override
    public DiariesDetailVo getDetail(Long id) {
        Assert.notNull(id, ErrorCode.SERVER_ERROR.getMsg());
        DiariesWithBLOBs diaries = diariesMapper.selectByPrimaryKey(id);
        DiariesDetailVo detailVo = new DiariesDetailVo();
        BeanUtil.copyProperties(diaries, detailVo);
        // 设置评论点赞数量
        Long commentCount = commentsMapper.selectCountByDiariesId(id);
        Long likeCount = likesMapper.selectCountByDiariesId(id);
        detailVo.setCommentNum(commentCount);
        detailVo.setLikeNum(likeCount);
        // 设置用户名
        Users users = userService.getInfo(diaries.getUserId());
        detailVo.setUserName(users.getUsername());
        // 设置图片路径
        List<String> images = buildImages(diaries.getImages());
        detailVo.setImages(images);

        return detailVo;
    }

    @Override
    public void publication(DiariesDto dto) {
        DiariesWithBLOBs diaries = new DiariesWithBLOBs();
        if (dto.getId() == null) {
            Long userId = dto.getUserId();
            diaries.setUserId(userId);
            diaries.setTitle(dto.getTitle());
            diaries.setContent(dto.getContent());
            List<String> images = dto.getImages();
            if (!images.isEmpty()) {
                String url = new JSONObject().set("url", new JSONArray(images)).toString();
                diaries.setImages(url);
            }
            diariesMapper.insertSelective(diaries);
            return;
        }
        DiariesWithBLOBs withBLOBs = diariesMapper.selectByPrimaryKey(dto.getId());
        if (withBLOBs == null){
            throw new BusinessException(ErrorCode.DIARIES_NOT_FOUND);
        }
        if (withBLOBs.getCreatedAt().getTime() < System.currentTimeMillis() - SEVEN_DAYS_MILLIS) {
            throw new BusinessException(ErrorCode.DIARIES_PUBLICATION_FAILURE);
        }
        List<String> images = dto.getImages();
        if (!images.isEmpty()) {
            String url = new JSONObject().set("url", new JSONArray(images)).toString();
            diaries.setImages(url);
        }
        diaries.setTitle(dto.getTitle());
        diaries.setContent(dto.getContent());
        diaries.setId(dto.getId());
        diaries.setUpdatedAt(new Date());
        diariesMapper.updateByPrimaryKeySelective(diaries);
    }

    @Override
    public void del(Long id) {
        if (id == null) {
            throw new BusinessException(ErrorCode.FAIL);
        }
        diariesMapper.deleteByPrimaryKey(id);
    }

    @Override
    public List<DiariesVo> selectByIds(List<Long> diariesIdList) {
        List<DiariesWithBLOBs> diariesList = diariesMapper.selectByIds(diariesIdList);
        if (CollectionUtil.isNotEmpty(diariesList)){
            List<DiariesVo> voList = BeanUtil.copyToList(diariesList, DiariesVo.class);
            diariesList.forEach(diariesWithBLOBs -> {
                List<String> images = buildImages(diariesWithBLOBs.getImages());
                voList.forEach(vo -> {
                    if (vo.getId().equals(diariesWithBLOBs.getId())) {
                        vo.setImages(images);
                    }
                });
            });
            // TODO 在循环查询数据库
            voList.forEach(vo -> {
               vo.setLikeNum(likesMapper.selectCountByDiariesId(vo.getId()));
               vo.setCommentNum(commentsMapper.selectCountByDiariesId(vo.getId()));
            });
            return voList;
        }
        return new ArrayList<>();
    }

    @Override
    public List<Diaries> selectByUserId(Long userId) {
        List<Diaries> result = diariesMapper.selectByUserId(userId);
        if (CollectionUtil.isNotEmpty(result)){
            return result;
        }else {
            return new ArrayList<>();
        }

    }


    private List<String> buildImages(String images) {
        JSONObject jsonObject = new JSONObject(images);
        if (jsonObject.isEmpty()) {
            return new ArrayList<>();
        }
        List<String> url = jsonObject.getJSONArray("url").toList(String.class);
        if (url == null) {
            return new ArrayList<>();
        }
        return url;
    }

    private Long getUserIdFromDiariesList(List<DiariesWithBLOBs> diariesList, Long diaryId) {
        return diariesList.stream()
                .filter(diary -> diary.getId().equals(diaryId))
                .findFirst()
                .map(DiariesWithBLOBs::getUserId)
                .orElse(null);
    }

}
